/**
 * Copyright (C) 2013 Guangzhou Tronlong Electronic Technology Co., Ltd. - www.tronlong.com
 *
 * @file csi_test.c
 *
 * @brief Example application main file.
 * This application continuously collects the specified frame number image,
 * calculates the time, prints the rate, checks the last frame image data.
 *
 * @author Tronlong <support@tronlong.com>
 *
 * @version V1.0
 *
 * @date 2022-8-15
 **/

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <stdint.h>
#include <sys/time.h>
#include <libgen.h>

#include "v4l2DevControl.h"
#include "csi.h"
#include "myLog.h"
#include "main.h"

// volatile bool g_quit = false;

// static void sig_handle(int signal)
// {
//     g_quit = true;
// }
/**
 * @description: 计算错误帧，默认data帧为0-256循环加一的值。
 * @param {uint8_t} *data
 * @param {uint32_t} width
 * @param {uint32_t} height
 * @return {*}
 */
static bool check_data(const uint8_t *data, uint32_t width, uint32_t height)
{
    uint32_t value = 0;
    uint32_t check_value;
    uint32_t error_num = 0;
    int status = 0;
    int i;

    for (i = 0; i <= width * height; i++) {
        check_value = value % 256;
        if (check_value != data[i]) {
            error_num = error_num + 1;
            status = 1;
        }
        value++;
    }
    qlog_w("byte error rate= %.1f%%\n", ((float)error_num / (width * height)) * 100);

    if (status == 0) {
        return true;
    } else {
        return false;
    }
}

/**
 * @description: CSI测试
 * @param {uint32_t} width
 * @param {uint32_t} height
 * @param {uint32_t} number
 * @return {*}
 */
int csiInit(uint32_t w,uint32_t h,uint32_t n)
{
    bool ret;
    struct _Params params;
    int frame_cnt = 0;
    struct timeval time_start, time_end, time_diff;
    int64_t timeStart = 0;
    double timeDiff = 0; 
    float average_rate;
    //设置视频捕获格式
    params.device = "/dev/video0";
    params.width = w;
    params.height = h;
    params.number = n;
    params.format = "BGGR";//像素格式
    // /* Ctrl+c handler */
    // signal(SIGINT, sig_handle);

    V4l2Device *camera = v4l2_device_open(params.device, params.type, params.format,
                                              params.width, params.height, params.fps);//open device

    

    printf("User Inputs:\n"
            "    Device       : %s\n"
            "    Fomat        : %s\n"
            "    Width        : %d\n"
            "    Height       : %d\n"
            "\n",
            params.device,
            params.format,
            params.width,
            params.height);

    v4l2_device_setup(camera); //init device
    v4l2_device_stream_on(camera); // start frame 

    timeStart = time_now();
    g_quit = false;
    while (! g_quit) {
        /* Get one frame */
        if (v4l2_device_get_buffer(camera, 3)) {    //在驱动的传出队列中，这些缓冲区已由驱动处理过，对于一个视频捕获设备，缓存区已经填充了视频数据，正等用户空间来认领；
            ++frame_cnt;

            if (params.number == frame_cnt) {
                g_quit = true;
            }

            qlog_w("Enter ctrl+c stop,Accept Frames: %d", frame_cnt);

        } else {
            qlog_e("Get frames failed!");
            break;
        }

        v4l2_device_put_buffer(camera);
    }

    /* Calculate the acquisition time and average rate */

    timeDiff = (double)((time_now()-timeStart)/1000);//us

    average_rate = (params.width * params.height * frame_cnt / (timeDiff / 1000000.0) / 1024 / 1024);
    qlog_w("time: %0.3fms, rate: %gMB/s", timeDiff / 1000, average_rate);

    /* Check the last frame */
    check_data((uint8_t *)camera->data, params.width, params.height);
    qlog_hexdump("csi data:",16,(uint8_t *)camera->data,128);
    ret = v4l2_device_stream_off(camera);
    if (!ret) {
        qlog_e("v4l2 device off failure.");
    }
    ret = v4l2_device_close(camera);
    if (!ret) {
        qlog_e("v4l2 device close failure.");
    }
    return 0;
}
